gtk: Run GtkWidgetClass event signals inside a GtkEventController
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 26 May 2017 16:55:30 +0000 (18:55 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Tue, 19 Sep 2017 16:39:03 +0000 (18:39 +0200)
This will allow further cleanups and optimizations in capture/target/bubble
event delivery. For simplicity, ATM every widget will receive its own
GtkEventControllerLegacy, it could be desirable to add finer control over
this in the future, so widgets that fully use event controllers for input
management can do away without this legacy piece.

gtk/gtkeventcontrollerlegacy.c [new file with mode: 0644]
gtk/gtkeventcontrollerlegacyprivate.h [new file with mode: 0644]
gtk/gtkwidget.c
gtk/gtkwidgetprivate.h
gtk/meson.build

diff --git a/gtk/gtkeventcontrollerlegacy.c b/gtk/gtkeventcontrollerlegacy.c
new file mode 100644 (file)
index 0000000..737312d
--- /dev/null
@@ -0,0 +1,56 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2017, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "config.h"
+#include "gtkeventcontrollerlegacyprivate.h"
+
+G_DEFINE_TYPE (GtkEventControllerLegacy, _gtk_event_controller_legacy,
+               GTK_TYPE_EVENT_CONTROLLER)
+
+static gboolean
+gtk_event_controller_legacy_handle_event (GtkEventController *controller,
+                                          const GdkEvent     *event)
+{
+  GtkWidget *widget = gtk_event_controller_get_widget (controller);
+
+  return gtk_widget_emit_event_signals (widget, event);
+}
+
+static void
+_gtk_event_controller_legacy_class_init (GtkEventControllerLegacyClass *klass)
+{
+  GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
+
+  controller_class->handle_event = gtk_event_controller_legacy_handle_event;
+}
+
+static void
+_gtk_event_controller_legacy_init (GtkEventControllerLegacy *controller)
+{
+}
+
+GtkEventController *
+_gtk_event_controller_legacy_new (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+  return g_object_new (GTK_TYPE_EVENT_CONTROLLER_LEGACY,
+                       "widget", widget,
+                       NULL);
+}
diff --git a/gtk/gtkeventcontrollerlegacyprivate.h b/gtk/gtkeventcontrollerlegacyprivate.h
new file mode 100644 (file)
index 0000000..3ec9426
--- /dev/null
@@ -0,0 +1,51 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2017, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#ifndef __GTK_EVENT_CONTROLLER_LEGACY_H__
+#define __GTK_EVENT_CONTROLLER_LEGACY_H__
+
+#include "gtkeventcontrollerprivate.h"
+#include "gtkwidgetprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_EVENT_CONTROLLER_LEGACY         (_gtk_event_controller_legacy_get_type ())
+#define GTK_EVENT_CONTROLLER_LEGACY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_EVENT_CONTROLLER_LEGACY, GtkEventControllerLegacy))
+#define GTK_EVENT_CONTROLLER_LEGACY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_EVENT_CONTROLLER_LEGACY, GtkEventControllerLegacyClass))
+#define GTK_IS_EVENT_CONTROLLER_LEGACY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_EVENT_CONTROLLER_LEGACY))
+#define GTK_IS_EVENT_CONTROLLER_LEGACY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_EVENT_CONTROLLER_LEGACY))
+#define GTK_EVENT_CONTROLLER_LEGACY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER_LEGACY, GtkEventControllerLegacyClass))
+
+typedef struct _GtkEventControllerLegacy GtkEventControllerLegacy;
+typedef struct _GtkEventControllerLegacyClass GtkEventControllerLegacyClass;
+
+struct _GtkEventControllerLegacy
+{
+  GtkEventController parent_instance;
+};
+
+struct _GtkEventControllerLegacyClass
+{
+  GtkEventControllerClass parent_class;
+};
+
+GType               _gtk_event_controller_legacy_get_type  (void) G_GNUC_CONST;
+GtkEventController *_gtk_event_controller_legacy_new       (GtkWidget *widget);
+
+#endif /* __GTK_EVENT_CONTROLLER_LEGACY_H__ */
index 4045ab837d6beeb9052e536e73410f238365efe4..8e369e0bd1e9c55889d435bef9ecc330e9b3ae52 100644 (file)
@@ -77,6 +77,7 @@
 #include "gtkcssshadowsvalueprivate.h"
 #include "gtkdebugupdatesprivate.h"
 #include "gsk/gskdebugprivate.h"
+#include "gtkeventcontrollerlegacyprivate.h"
 
 #include "inspector/window.h"
 
@@ -3847,6 +3848,8 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
   gtk_css_node_set_visible (priv->cssnode, priv->visible);
   /* need to set correct type here, and only class has the correct type here */
   gtk_css_node_set_widget_type (priv->cssnode, G_TYPE_FROM_CLASS (g_class));
+
+  gtk_widget_init_legacy_controller (widget);
 }
 
 
@@ -6466,16 +6469,14 @@ static gboolean
 gtk_widget_real_button_event (GtkWidget      *widget,
                               GdkEventButton *event)
 {
-  return _gtk_widget_run_controllers (widget, (GdkEvent *) event,
-                                      GTK_PHASE_BUBBLE);
+  return GDK_EVENT_PROPAGATE;
 }
 
 static gboolean
 gtk_widget_real_motion_event (GtkWidget      *widget,
                               GdkEventMotion *event)
 {
-  return _gtk_widget_run_controllers (widget, (GdkEvent *) event,
-                                      GTK_PHASE_BUBBLE);
+  return GDK_EVENT_PROPAGATE;
 }
 
 static gboolean
@@ -6518,10 +6519,6 @@ gtk_widget_real_touch_event (GtkWidget     *widget,
   gboolean return_val;
   gint signum;
 
-  if (!event->emulating_pointer)
-    return _gtk_widget_run_controllers (widget, (GdkEvent*) event,
-                                        GTK_PHASE_BUBBLE);
-
   if (event->type == GDK_TOUCH_BEGIN ||
       event->type == GDK_TOUCH_END)
     {
@@ -6587,8 +6584,7 @@ static gboolean
 gtk_widget_real_grab_broken_event (GtkWidget          *widget,
                                    GdkEventGrabBroken *event)
 {
-  return _gtk_widget_run_controllers (widget, (GdkEvent*) event,
-                                      GTK_PHASE_BUBBLE);
+  return GDK_EVENT_PROPAGATE;
 }
 
 #define WIDGET_REALIZED_FOR_EVENT(widget, event) \
@@ -6827,7 +6823,7 @@ static gint
 gtk_widget_event_internal (GtkWidget      *widget,
                            const GdkEvent *event)
 {
-  gboolean return_val = FALSE, handled;
+  gboolean return_val = FALSE;
   GdkEvent *event_copy;
 
   /* We check only once for is-still-visible; if someone
@@ -6838,7 +6834,27 @@ gtk_widget_event_internal (GtkWidget      *widget,
   if (!event_window_is_still_viewable (event))
     return TRUE;
 
-  g_object_ref (widget);
+  /* Non input events get handled right away */
+  switch (event->type)
+    {
+    case GDK_VISIBILITY_NOTIFY:
+    case GDK_EXPOSE:
+    case GDK_NOTHING:
+    case GDK_DELETE:
+    case GDK_DESTROY:
+    case GDK_CONFIGURE:
+    case GDK_MAP:
+    case GDK_UNMAP:
+    case GDK_WINDOW_STATE:
+    case GDK_PROPERTY_NOTIFY:
+    case GDK_SELECTION_CLEAR:
+    case GDK_SELECTION_REQUEST:
+    case GDK_SELECTION_NOTIFY:
+      return gtk_widget_emit_event_signals (widget, event);
+    default:
+      break;
+    }
+
   event_copy = gdk_event_copy (event);
 
   translate_event_coordinates (event_copy, widget);
@@ -6846,18 +6862,39 @@ gtk_widget_event_internal (GtkWidget      *widget,
   if (widget == gtk_get_event_target (event_copy))
     return_val |= _gtk_widget_run_controllers (widget, event_copy, GTK_PHASE_TARGET);
 
-  g_signal_emit (widget, widget_signals[EVENT], 0, event_copy, &handled);
-  return_val |= handled | !WIDGET_REALIZED_FOR_EVENT (widget, event_copy);
+  /* XXX: Tooltips should be handled through captured events in the toplevel */
+  if (event_copy->type == GDK_FOCUS_CHANGE)
+    {
+      if (event_copy->focus_change.in)
+        _gtk_tooltip_focus_in (widget);
+      else
+        _gtk_tooltip_focus_out (widget);
+    }
+
+  return_val |= _gtk_widget_run_controllers (widget, event_copy, GTK_PHASE_BUBBLE);
+  gdk_event_free (event_copy);
+
+  return return_val;
+}
+
+gboolean
+gtk_widget_emit_event_signals (GtkWidget      *widget,
+                               const GdkEvent *event)
+{
+  gboolean return_val = FALSE, handled;
+
+  g_object_ref (widget);
+
+  g_signal_emit (widget, widget_signals[EVENT], 0, event, &handled);
+  return_val |= handled | !WIDGET_REALIZED_FOR_EVENT (widget, event);
   if (!return_val)
     {
       gint signal_num;
 
-      switch (event_copy->type)
+      switch (event->type)
        {
         case GDK_TOUCHPAD_SWIPE:
         case GDK_TOUCHPAD_PINCH:
-          return_val |= _gtk_widget_run_controllers (widget, event_copy, GTK_PHASE_BUBBLE);
-          /* Fall through */
         case GDK_PAD_BUTTON_PRESS:
         case GDK_PAD_BUTTON_RELEASE:
         case GDK_PAD_RING:
@@ -6908,11 +6945,7 @@ gtk_widget_event_internal (GtkWidget      *widget,
          signal_num = LEAVE_NOTIFY_EVENT;
          break;
        case GDK_FOCUS_CHANGE:
-         signal_num = event_copy->focus_change.in ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
-         if (event_copy->focus_change.in)
-           _gtk_tooltip_focus_in (widget);
-         else
-           _gtk_tooltip_focus_out (widget);
+         signal_num = event->focus_change.in ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
          break;
        case GDK_CONFIGURE:
          signal_num = CONFIGURE_EVENT;
@@ -6948,23 +6981,22 @@ gtk_widget_event_internal (GtkWidget      *widget,
          signal_num = GRAB_BROKEN_EVENT;
          break;
        default:
-         g_warning ("gtk_widget_event(): unhandled event type: %d", event_copy->type);
+         g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
          signal_num = -1;
          break;
        }
       if (signal_num != -1)
         {
-         g_signal_emit (widget, widget_signals[signal_num], 0, event_copy, &handled);
+         g_signal_emit (widget, widget_signals[signal_num], 0, event, &handled);
           return_val |= handled;
         }
     }
-  if (WIDGET_REALIZED_FOR_EVENT (widget, event_copy))
-    g_signal_emit (widget, widget_signals[EVENT_AFTER], 0, event_copy);
+  if (WIDGET_REALIZED_FOR_EVENT (widget, event))
+    g_signal_emit (widget, widget_signals[EVENT_AFTER], 0, event);
   else
     return_val = TRUE;
 
   g_object_unref (widget);
-  gdk_event_free (event_copy);
 
   return return_val;
 }
@@ -15552,3 +15584,14 @@ gtk_widget_get_pass_through (GtkWidget *widget)
 {
   return widget->priv->pass_through;
 }
+
+void
+gtk_widget_init_legacy_controller (GtkWidget *widget)
+{
+  GtkEventController *controller;
+
+  controller = _gtk_event_controller_legacy_new (widget);
+  g_object_set_data_full (G_OBJECT (widget),
+                          "gtk-widget-legacy-event-controller",
+                          controller, g_object_unref);
+}
index 4c76ca1efaa69a529123f786d0f1aaf032689365..6e0b746a2c8a51249d9ddc2be19f5f97937774be 100644 (file)
@@ -334,6 +334,12 @@ void              gtk_widget_set_pass_through              (GtkWidget *widget,
                                                             gboolean   pass_through);
 gboolean          gtk_widget_get_pass_through              (GtkWidget *widget);
 
+gboolean          gtk_widget_emit_event_signals            (GtkWidget      *widget,
+                                                            const GdkEvent *event);
+
+void              gtk_widget_init_legacy_controller        (GtkWidget *widget);
+
+
 /* inline getters */
 
 static inline GtkWidget *
index 20b0410555efedda023b42c574a7d4f4d7bad2a0..5dc3188da9e237a50cb4bb41289ba8dcd529eee4 100644 (file)
@@ -146,6 +146,7 @@ gtk_public_sources = files([
   'gtkentrybuffer.c',
   'gtkentrycompletion.c',
   'gtkeventcontroller.c',
+  'gtkeventcontrollerlegacy.c',
   'gtkexpander.c',
   'gtkfilechooser.c',
   'gtkfilechooserbutton.c',
@@ -364,6 +365,7 @@ gtk_public_sources = files([
 gtk_private_type_headers = files([
   'gtkcsstypesprivate.h',
   'gtktexthandleprivate.h',
+  'gtkeventcontrollerlegacyprivate.h',
 ])
 
 gtk_private_headers = gtk_private_type_headers + files([